﻿using System;
using System.Collections.ObjectModel;
using System.Device.Location;
using System.Linq;
using System.Net;
using GalaSoft.MvvmLight.Threading;
using Hammock;
using Hammock.Web;
using MyMeetup.Entities;
using Newtonsoft.Json;

namespace MyMeetup
{
    public class DataService
    {
        private bool _isInErrorState;

        

        /// <summary>
        /// Gets the Member object of the logged on user
        /// </summary>
        /// <param name="callback"></param>
        public void GetMember(Action<Member> callback, Action<RequestError> errorCallback)
        {
            var request = new MeetupRequest("2/members", WebMethod.Get);
            request.AddParameter("member_id", "self");

            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
            {
                var user = ((Members)JsonConvert.DeserializeObject<Members>(restResponse.Content)).Items[0];
                CallbackInternal(callback, user);

            });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);
        }



        /// <summary>
        /// Gets a member's profile for a given group
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="groupId"></param>
        /// <param name="callback"></param>
        public void GetMemberProfile(long userId, int groupId, Action<Profile> callback, Action<RequestError> errorCallback)
        {
            MeetupRequest request = new MeetupRequest("2/profiles", WebMethod.Get);
            request.AddParameter("member_id", userId.ToString());
            request.AddParameter("group_id", groupId.ToString());

            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
            {
                var resp = (JsonConvert.DeserializeObject<Profiles>(restResponse.Content)).Items;
                var profile = resp.Count > 0 ? resp[0] : new Profile();
                CallbackInternal(callback, profile);
            });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);
        }



        /// <summary>
        /// not used at this time. do I have plans for this? Hmm....
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="callback"></param>
        public void GetMember(long userId, Action<Member> callback, Action<RequestError> errorCallback)
        {
            var request = new MeetupRequest("2/members", WebMethod.Get);
            request.AddParameter("member_id", userId.ToString());

            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
                {
                    var user = ((Members)JsonConvert.DeserializeObject<Members>(restResponse.Content)).Items[0];
                    CallbackInternal(callback, user);
                });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);
        }


        public void GetNews(long userId, Action<ObservableCollection<Activity>> callback, Action<RequestError> errorCallback)
        {
            var request = new MeetupRequest("activity", WebMethod.Get);
            request.AddParameter("member_id", userId.ToString());

            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
            {
                var news = new ObservableCollection<Activity>();
                var activity = JsonConvert.DeserializeObject<Activities>(restResponse.Content).Items;
                activity.ForEach(news.Add);
                CallbackInternal(callback, news);

            });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);
        }



        public void GetGroups(long userId, Action<ObservableCollection<IGroup>> callback, Action<RequestError> errorCallback)
        {

            var request = new MeetupRequest("2/groups", WebMethod.Get);
            request.AddParameter("member_id", userId.ToString());
            request.AddParameter("text_format", "plain");
            request.AddParameter("fields", "self");

            var callback2 = new RestCallback(
                (restRequest, restResponse, userState) =>
                {

                    var groups = new ObservableCollection<IGroup>();
                    var resp = JsonConvert.DeserializeObject<Groups>(restResponse.Content);
                    resp.Items.ForEach(groups.Add);
                    CallbackInternal(callback, groups);

                });

            var helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);
        }


        public void GetGroupById(int groupId, Action<IGroup> callback, Action<RequestError> errorCallback)
        {

            var request = new MeetupRequest("2/groups", WebMethod.Get);
            request.AddParameter("group_id", groupId.ToString());
            request.AddParameter("fields", "self,join_info");
            var callback2 = new RestCallback(
                (restRequest, restResponse, userState) =>
                {
                    var resp = JsonConvert.DeserializeObject<Groups>(restResponse.Content);
                    var group = resp.Items.Count > 0 ? resp.Items[0] : new Group();
                    CallbackInternal(callback, group);

                });

            var helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);
        }


        public void GetEventsForUser(long userId, Action<ObservableCollection<Event>> callback, Action<RequestError> errorCallback)
        {

            MeetupRequest request = new MeetupRequest("2/events", WebMethod.Get);
            request.AddParameter("member_id", userId.ToString());
            request.AddParameter("text_format", "plain");
            request.AddParameter("fields", "self,rsvp_rules,group_photo");
            request.AddParameter("status", "upcoming,proposed,suggested");

            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
                {
                    var events = new ObservableCollection<Event>();
                    var resp = JsonConvert.DeserializeObject<Events>(restResponse.Content).Items;

                    resp = resp.OrderBy(e => e.time == 0).ThenBy(e => e.time).ToList();

                    resp.ForEach(events.Add);

                    CallbackInternal(callback, events);

                });


            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);
        }


        public void GetEventsForGroup(int groupId, int count, int offset, Action<ObservableCollection<Event>> callback, Action<RequestError> errorCallback)
        {
            MeetupRequest request = new MeetupRequest("2/events", WebMethod.Get);
            request.AddParameter("group_id", groupId.ToString());
            request.AddParameter("text_format", "plain");
            request.AddParameter("fields", "self,rsvp_rules");
            request.AddParameter("desc", "desc");
            request.AddParameter("page", count.ToString());
            request.AddParameter("offset", offset.ToString());
            string status = "suggested,upcoming,past";
           
            request.AddParameter("status", status);


            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
            {
                var events = new ObservableCollection<Event>();
                var resp = JsonConvert.DeserializeObject<Events>(restResponse.Content).Items;
                resp.ForEach(events.Add);
                CallbackInternal(callback, events);
               
            });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);

        }


        public void GetPastEventsForGroup(int groupId, Action<ObservableCollection<Event>> callback, Action<RequestError> errorCallback)
        {
            MeetupRequest request = new MeetupRequest("2/events", WebMethod.Get);
            request.AddParameter("group_id", groupId.ToString());
            request.AddParameter("text_format", "plain");
            request.AddParameter("fields", "self,rsvp_rules");
            request.AddParameter("desc", "desc");
            request.AddParameter("page", "20");
            string status = "past";

            request.AddParameter("status", status);

            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
            {
                System.Threading.Thread.Sleep(new TimeSpan(0,0,5));
                var events = new ObservableCollection<Event>();
                var resp = JsonConvert.DeserializeObject<Events>(restResponse.Content).Items;
                resp.ForEach(events.Add);
                CallbackInternal(callback, events);

            });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);
        }


        public void GetGroupPhoto(int groupId, Action<Photo> callback, Action<RequestError> errorCallback)
        {
            MeetupRequest request = new MeetupRequest("2/photos", WebMethod.Get);
            request.AddParameter("group_id",groupId.ToString());
            request.AddParameter("page", "1");

           
            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
            {
                var photo = JsonConvert.DeserializeObject<Photos>(restResponse.Content).Items.FirstOrDefault();
                CallbackInternal(callback, photo);
                
            });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);

        }


        public void GetGroupPhotoAlbums(int groupId, Action<ObservableCollection<Album>> callback, Action<RequestError> errorCallback)
        {
            MeetupRequest request = new MeetupRequest("2/photo_albums", WebMethod.Get);
            request.AddParameter("group_id", groupId.ToString());

            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
                                                 {
                                                     var albums = new ObservableCollection<Album>();
                                                     var resp =
                                                         JsonConvert.DeserializeObject<Albums>(restResponse.Content).
                                                             Items;
                                                     resp.ForEach(albums.Add);
                                                     CallbackInternal(callback, albums);
                                                 });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);

        }



        public void GetAlbumPhotos(long albumId, Action<ObservableCollection<Photo>> callback, Action<RequestError> errorCallback)
        {
            MeetupRequest request = new MeetupRequest("2/photos", WebMethod.Get);
            request.AddParameter("photo_album_id", albumId.ToString());
            request.AddParameter("nonsense", DateTime.Now.Ticks.ToString());

            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
                                                 {
                                                     var resp =
                                                         JsonConvert.DeserializeObject<Photos>(restResponse.Content).
                                                             Items;
                                                     var photos = new ObservableCollection<Photo>();
                                                     resp.ForEach(photos.Add);
                                                     CallbackInternal(callback, photos);
                                                 });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);
        }


        public void GetPhoto(long photoId, Action<Photo> callback, Action<RequestError> errorCallback)
        {
            MeetupRequest request = new MeetupRequest("2/photos", WebMethod.Get);
            //request.AddParameter("photo_album_id", albumId.ToString());
            request.AddParameter("photo_id", photoId.ToString());

            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
                                                 {
                                                     var photo =
                                                         JsonConvert.DeserializeObject<Photos>(restResponse.Content).
                                                             Items[0];
                                                     CallbackInternal(callback, photo);
                                                 });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);
        }


        public void GetEventPhotos(string eventId, Action<ObservableCollection<Photo>> callback, Action<RequestError> errorCallback)
        {
            MeetupRequest request = new MeetupRequest("2/photos", WebMethod.Get);
            request.AddParameter("event_id", eventId);

            var callback2 = new RestCallback(
                              (restRequest, restResponse, userState) =>
                                  {
                                      var photos = new ObservableCollection<Photo>();
                                      var resp = JsonConvert.DeserializeObject<Photos>(restResponse.Content).Items;
                                      resp.ForEach(photos.Add);
                                      CallbackInternal(callback, photos);
                              });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);


        }




        public void GetEventAttendees(string eventId, Action<ObservableCollection<Rsvp>> callback, Action<RequestError> errorCallback)
        {
            MeetupRequest request = new MeetupRequest("2/rsvps", WebMethod.Get);
            request.AddParameter("event_id", eventId);
            request.AddParameter("rsvp", "yes");    // only get members who's rsvp = yes

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute((restRequest, restResponse, userState) =>
                                    {
                                        var rsvps = new ObservableCollection<Rsvp>();
                                        var resp = JsonConvert.DeserializeObject<Rsvps>(restResponse.Content).Items;
                                        resp.ForEach(rsvps.Add);
                                        CallbackInternal(callback, rsvps);

            }, errorCallback);
        }


        public void GetEventReviews(string eventId, Action<ObservableCollection<EventReview>> callback, Action<RequestError> errorCallback )
        {
            var request = new MeetupRequest("2/event_ratings", WebMethod.Get);
            request.AddParameter("event_id", eventId);
            request.AddParameter("nonsense", DateTime.Now.Ticks.ToString());

            var helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute((restRequest, restResponse, userState) =>
                                    {
                                        var ratings = new ObservableCollection<EventReview>();
                                        var resp = JsonConvert.DeserializeObject<EventReviews>(restResponse.Content).Items;
                                        foreach (var eventReview in resp.Where(eventReview => eventReview.review != null))
                                        {
                                            ratings.Add(eventReview);
                                        }

                                        CallbackInternal(callback, ratings);
                                    }, errorCallback);
        }


        public void GetRsvpForUser(long userId, string eventId, Action<Rsvp> callback, Action<RequestError> errorCallback)
        {
            MeetupRequest request = new MeetupRequest("2/rsvps", WebMethod.Get);
            request.AddParameter("event_id", eventId);
            request.AddParameter("member_id", userId.ToString()); 

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute((restRequest, restResponse, userState) =>
            {
                var rsvp = (JsonConvert.DeserializeObject<Rsvps>(restResponse.Content).Items)[0];
                CallbackInternal(callback, rsvp);

            }, errorCallback);
        }




        public void SearchForGroups(string topic, GeoCoordinate location, int radius, Action<ObservableCollection<GroupSearchItem>> callback, Action<RequestError> errorCallback)
        {
            var request = new MeetupRequest("groups", WebMethod.Get);
            request.AddParameter("topic", topic);
            request.AddParameter("radius", radius.ToString());
            request.AddParameter("lat", location.Latitude.ToString().Replace(',','.'));
            request.AddParameter("lon", location.Longitude.ToString().Replace(',', '.'));

            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
                                                 {
                                                     var groups = new ObservableCollection<GroupSearchItem>();
                                                     var resp =
                                                         JsonConvert.DeserializeObject<GroupSearchResults>(
                                                             restResponse.Content).Items;
                                                     resp.ForEach(groups.Add);
                                                     CallbackInternal(callback, groups);
                                                 });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);
        }


        public void PostEventRsvp(string eventId, RSVPType rsvpType, string comments, int guestCount, Action<RsvpResponse> callback, Action<RequestError> errorCallback )
        {

            var request = new MeetupRequest("2/rsvp", WebMethod.Post);
            request.AddParameter("event_id", eventId.ToString());
            request.AddParameter("rsvp", rsvpType.ToString());
            request.AddParameter("guests", guestCount.ToString()); 
            if (comments.Length > 0) request.AddParameter("comments", comments);

            var helper = new RequestHelper(request, HttpStatusCode.Created);

            helper.BeginExecute((restRequest, restResponse, userState) =>
                                    {
                                        var rsvpResponse =
                                            JsonConvert.DeserializeObject<RsvpResponse>(restResponse.Content);
                                        CallbackInternal(callback, rsvpResponse);
                                    }, errorCallback);

        }


        public void PostEventRating(EventReview rating, Action<EventReview> callback, Action<RequestError> errorCallback)
        {
            var request = new MeetupRequest("2/event_rating", WebMethod.Post);
            request.AddParameter("rating", rating.rating.ToString());
            request.AddParameter("event_id", rating.event_id);
            request.AddParameter("comment", rating.review);

            var helper = new RequestHelper(request, HttpStatusCode.Created);
            helper.BeginExecute((restRequest, restResponse, userState) =>
                                    {
                                        var resp = JsonConvert.DeserializeObject<EventReview>(restResponse.Content);
                                        CallbackInternal(callback, resp);
                                    }, errorCallback
                );
        }


        public void UploadPhotoToAlbum(long albumId, string filename, System.IO.Stream photo, Action<long> callback, Action<RequestError> errorCallback)
        {
            UploadPhotoInternal(string.Empty, albumId.ToString(), filename, photo, callback, errorCallback);
        }


        public void UploadPhotoToEvent(string eventId, string filename, System.IO.Stream photo, Action<long> callback, Action<RequestError> errorCallback)
        {
            UploadPhotoInternal(eventId, string.Empty, filename, photo, callback, errorCallback);
        }


        private void UploadPhotoInternal(string eventId, string albumId, string filename, System.IO.Stream photo, Action<long> callback, Action<RequestError> errorCallback)
        {
            var request = new MeetupRequest("2/photo", WebMethod.Post);
            if(!string.IsNullOrEmpty(eventId)) request.AddParameter("event_id", eventId);
            if(!string.IsNullOrEmpty(albumId)) request.AddParameter("photo_album_id", albumId);
            request.AddFile("photo", filename, photo);

            var helper = new RequestHelper(request, HttpStatusCode.Created);
            helper.BeginExecute((restRequest, restResponse, userState) =>
            {
                var resp =
                    JsonConvert.DeserializeObject<UploadedPhotoResponse>(restResponse.Content);
                System.Threading.Thread.Sleep(new TimeSpan(0, 0, 3)); // need a few seconds for GetPhoto command to find it
                CallbackInternal(callback, resp.event_photo_id);
            }, errorCallback);
        }



        public void GetAllTopics(Action<ObservableCollection<Topic>> callback, Action<RequestError> errorCallback)
        {
            MeetupRequest request = new MeetupRequest("topics", WebMethod.Get);

            var callback2 = new RestCallback((restRequest, restResponse, userState) =>
            {
                var topics = new ObservableCollection<Topic>();
                var resp = JsonConvert.DeserializeObject<Topics>(restResponse.Content).Items;
                resp.ForEach(topics.Add);
                CallbackInternal(callback, topics);

            });

            RequestHelper helper = new RequestHelper(request, HttpStatusCode.OK);
            helper.BeginExecute(callback2, errorCallback);
        }






        public void Checkin(string eventId, Action<Checkin> callback, Action<RequestError> errorCallback)
        {

                var request = new MeetupRequest("2/checkin", WebMethod.Post);
                request.AddParameter("event_id", eventId);
            var helper = new RequestHelper(request, HttpStatusCode.Created);
            helper.BeginExecute((restRequest, restResponse, userState) =>
                                                         {
                                                             var checkin =
                                                                 JsonConvert.DeserializeObject<Checkin>(restResponse.Content);
                                                             CallbackInternal(callback, checkin);

                                                         }, errorCallback);

        }


        private void CallbackInternal<T>(Action<T> callback, T state)
        {
            DispatcherHelper.CheckBeginInvokeOnUI(() =>
                                                      {
                                                          GlobalLoading.Instance.IsLoading = false;
                                                          callback(state);
                                                      });
        }
    }
}
